/**
**********************************************************************
* @file     main.c
* @brief    对文件的简要说明
* @details  对文件的详细说明
* @author   jcai
* @date     2022-05-06 15:49:43
* @copyright Copyright &copy; 2022 wy1107412334@163.com All rights reserved
* @version  v0.0.1
*
* \n Email:  wy1107412334@163.com
* \n Blog:   None
* \n Github: https://github.com/wy1107412334
* \n Gitee:  https://gitee.com/git.git1107412334.com
*
**********************************************************************
* @note
* None.
**********************************************************************
* @attention
* None.
**********************************************************************
@verbatim
@endverbatim
**********************************************************************
* @par 历史记录
* 1. v0.0.1: jcai, 2022-05-06 15:49:43
*   - 首次编写
*
*<center>Copyright &copy; 2022 wy1107412334@163.com All rights reserved</center>
**********************************************************************
*/

/* 头文件导入区 --------------------------------------------------- */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>
#include <SDL/SDL_video.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_thread.h>
#include <SDL/SDL_mutex.h>
#include <SDL/SDL_ttf.h>
#include <SDL/SDL_events.h>
#include <SDL/SDL_timer.h>
#include <SDL/SDL_keysym.h>



// 窗口属性
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

// 将要使用的表面
SDL_Surface *screen = NULL;
SDL_Surface *images[ 5 ] = { NULL, NULL, NULL, NULL, NULL };
SDL_Surface *buffer = NULL;

// 事件结构体
SDL_Event event;

// 线程的句柄
SDL_Thread *producerThread = NULL;
SDL_Thread *consumerThread = NULL;

// 互斥锁
SDL_mutex *bufferLock = NULL;
// 条件变量
SDL_cond *canProduce = NULL;
SDL_cond *canConsume = NULL;



SDL_Surface *load_image(const char *file)
{
    SDL_Surface *loadedImage = NULL;
    SDL_Surface *optimizedImage = NULL;

    // 通过 SDL_imag 模块加载图片
    loadedImage = IMG_Load(file);
    if (!loadedImage)   return NULL;

    optimizedImage = SDL_DisplayFormat(loadedImage);
    SDL_FreeSurface(loadedImage);
    if (optimizedImage)
    {
        // 映射关键色
        uint32_t keycolor = SDL_MapRGB(optimizedImage->format, 0, 0xff, 0xff);
        // 将所有颜色为 RGB(0x00, 0xff, 0xff) 的像素设为透明
        SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, keycolor);
    }

    return optimizedImage;
}

void apply_surface(int x, int y, SDL_Surface *src, SDL_Surface *dst,
                   const SDL_Rect *clip)
{
    SDL_Rect offset;

    offset.x = x;
    offset.y = y;

    SDL_BlitSurface(src, (SDL_Rect *)clip, dst, &offset);
}

int init()
{
    if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
        return -1;

    screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP,
                              SDL_SWSURFACE);
    if (!screen)
    {
        SDL_Quit();
        return -2;
    }

    SDL_WM_SetCaption("Producer / Consumer Test", NULL );

    // 创建互斥锁
    bufferLock = SDL_CreateMutex();

    // 创建条件变量
    canProduce = SDL_CreateCond();
    canConsume = SDL_CreateCond();

    // 给窗口背景填充白色
    SDL_FillRect(screen, &screen->clip_rect,
                 SDL_MapRGB(screen->format, 0xff, 0xff, 0xff));

    return 0;
}

int load_files()
{
    // 加载图片
    images[0] = load_image("1.png");
    if (!images[0])    return -1;
    images[1] = load_image("2.png");
    if (!images[1])
    {
        SDL_FreeSurface(images[0]);
        return -2;
    }
    images[2] = load_image("3.png");
    if (!images[2])
    {
        SDL_FreeSurface(images[0]);
        SDL_FreeSurface(images[1]);
        return -3;
    }
    images[3] = load_image("4.png");
    if (!images[3])
    {
        SDL_FreeSurface(images[0]);
        SDL_FreeSurface(images[1]);
        SDL_FreeSurface(images[2]);
        return -4;
    }
    images[4] = load_image("5.png");
    if (!images[4])
    {
        SDL_FreeSurface(images[0]);
        SDL_FreeSurface(images[1]);
        SDL_FreeSurface(images[2]);
        SDL_FreeSurface(images[3]);
        return -5;
    }

    return 0;
}

void clean_up()
{
    int i;

    // 销毁互斥锁
    SDL_DestroyMutex( bufferLock );

    // 销毁条件变量
    SDL_DestroyCond( canProduce );
    SDL_DestroyCond( canConsume );

    // 释放表面
    for(i = 0; i < 5; i++ )
        SDL_FreeSurface( images[ i ] );

    SDL_Quit();
}

void produce( int x, int y )
{
    //Lock
    SDL_mutexP( bufferLock );

    //If the buffer is full
    if( buffer != NULL )
    {
        //Wait for buffer to be cleared
        SDL_CondWait( canProduce, bufferLock );
    }

    //Fill and show buffer
    buffer = images[ rand() % 5 ];
    apply_surface(x, y, buffer, screen, NULL);

    //Update the screen
    SDL_Flip( screen );

    //Unlock
    SDL_mutexV( bufferLock );

    //Signal consumer
    SDL_CondSignal( canConsume );
}

void consume( int x, int y )
{
    //Lock
    SDL_mutexP( bufferLock );

    //If the buffer is empty
    if( buffer == NULL )
    {
        //Wait for buffer to be filled
        SDL_CondWait( canConsume, bufferLock );
    }

    //Show and empty buffer
    apply_surface(x, y, buffer, screen, NULL);
    buffer = NULL;

    //Update the screen
    SDL_Flip( screen );

    //Unlock
    SDL_mutexV( bufferLock );

    //Signal producer
    SDL_CondSignal( canProduce );
}

int producer( void *data )
{
    //The offset of the blit.
    int y = 10;
    int p;

    //Seed random
    srand( SDL_GetTicks() );

    //Produce
    for(p = 0; p < 5; p++)
    {
        //Wait
        SDL_Delay( rand() % 1000 );

        //Produce
        produce( 10, y );

        //Move down
        y += 90;
    }

    return 0;
}

int consumer( void *data )
{
    //The offset of the blit.
    int y = 10;
    int p;

    for(p = 0; p < 5; p++)
    {
        //Wait
        SDL_Delay( rand() % 1000 );

        //Consume
        consume( 330, y );

        //Move down
        y += 90;
    }

    return 0;
}




/**
**********************************************************************
* @brief    简要说明
* @details  详细说明
* @param    none
* @param[in]     a: 该参数用于输入
* @param[in,out] b: 该参数用于输入和输出
* @param[out]    c: 该参数用于输出
* @retval  none
* @retval  0 函数成功
* @retval  1 函数失败
* @return  返回0成功；否则失败
* @note    none
*/
int main(int argc, char *argv[])
{
    // 退出标志
    int quit = 0;

    if (init() != 0)
    {
        fprintf(stderr, "SDL初始化失败\n");
        return EXIT_FAILURE;
    }
    if (load_files() != 0)
    {
        fprintf(stderr, "SDL加载 background.png 失败\n");
        return EXIT_FAILURE;
    }

    // 填充背景色
    SDL_FillRect(screen, &screen->clip_rect,
                 SDL_MapRGB(screen->format, 0x80, 0x80, 0x80));

    // 更新窗口
    if (SDL_Flip(screen) == -1)
    {
        fprintf(stderr, "SDL更新窗口失败\n");
        return EXIT_FAILURE;
    }

    // 创建线程
    producerThread = SDL_CreateThread( producer, NULL );
    consumerThread = SDL_CreateThread( consumer, NULL );
    // 等待线程退出
    SDL_WaitThread( producerThread, NULL );
    SDL_WaitThread( consumerThread, NULL );

    while (!quit)
    {
        // 处理SDL的事件
        while (SDL_PollEvent(&event))
        {
            // 如果用户点击了窗口右上角的关闭按钮
            if (event.type == SDL_QUIT)
            {
                quit = 1;
                break;
            }
        }
    }

    clean_up();

    return 0;
}


/***  Copyright (C) 2022 wy1107412334@163.com All rights reserved ***/
/****************************** END OF FILE *************************/

